/*
 * Window.cpp
 *
 *  Created on: 29-11-2010
 *      Author: Przemek
 */
#include "Window.hpp"
#include "InitVideoException.hpp"
#include "utils/Timer.hpp"
using namespace std;

const Dimension Window::BASE_SIZE(800, 600);
const bool Window::FULLSCREEN = false;
const Uint32 Window::SLEEP_MILLIS_ON_IDLE = 50;

Window::Window() :
	running(false)
{
}

Window::~Window()
{
	if(SDL_WasInit(SDL_INIT_VIDEO))
	{
		SDL_Quit();
	}
}

void Window::init()
{
	initSDLForOgl();
	initOglSettings();
	SDL_WM_SetCaption("the-game-of-life", NULL);
	userInterface = new UserInterface(BASE_SIZE);
	windowSizeChanged(BASE_SIZE);
}

void Window::run()
{
	running = true;
	SDL_Event event;
	Timer timer;
	while(running)
	{
		timer.stop();
		const float drawFrameTimeInSeconds = timer.getSeconds();
		timer.start();
		while(SDL_PollEvent(&event))
		{
			processSDLEvent(event);
		}
		if(active)
		{
			userInterface->updateWithDeltaTime(drawFrameTimeInSeconds);
			drawFrame();
		}
		else
		{
			SDL_Delay(SLEEP_MILLIS_ON_IDLE);
		}
	}
}

void Window::initSDLForOgl()
{
	if(SDL_Init(SDL_INIT_VIDEO) < 0)
	{
		throw InitVideoException("Cannot init SDL_VIDEO");
	}

	if(SDL_SetVideoMode(BASE_SIZE.getWidth(), BASE_SIZE.getHeight(), 0, getVideoModeFlags()) == NULL)
	{
		throw InitVideoException("Cannot set video mode.");
	}
	SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
}

Uint32 Window::getVideoModeFlags()
{
	Uint32 videoModeFlags = SDL_OPENGL;
	if(FULLSCREEN)
	{
		videoModeFlags |= SDL_FULLSCREEN;
	}
	else
	{
		videoModeFlags |= SDL_RESIZABLE;
	}
	return videoModeFlags;
}

void Window::windowSizeChanged(const Dimension& windowSize)
{
	glViewport(0, 0, static_cast<int> (windowSize.getWidth()),
			static_cast<int> (windowSize.getHeight()));

	glMatrixMode( GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0.0f, windowSize.getWidth(), windowSize.getHeight(), 0.0f, -1.0f, 1.0f);

	userInterface->windowSizeChanged(windowSize);
}

void Window::initOglSettings()
{
	glShadeModel( GL_SMOOTH);
	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
	glDisable( GL_DEPTH_TEST);
	glEnable( GL_SCISSOR_TEST);
}

void Window::processSDLEvent(const SDL_Event& event)
{
	switch(event.type)
	{
		case SDL_QUIT:
			running = false;
			break;
		case SDL_ACTIVEEVENT:
			processSDLActiveEvent(event.active);
			break;
		case SDL_VIDEORESIZE:
			windowSizeChanged(Dimension(event.resize.w, event.resize.h));
			break;
		case SDL_MOUSEBUTTONDOWN:
			userInterface->processMouseButtonEvent(event.button);
			break;
		case SDL_MOUSEBUTTONUP:
			userInterface->processMouseButtonEvent(event.button);
			break;
		case SDL_MOUSEMOTION:
			userInterface->processMouseMotionEvent(event.motion);
			break;
		case SDL_KEYUP:
			userInterface->processKeyEvent(event.key);
		default:
			break;
	}
}

void Window::processSDLActiveEvent(const SDL_ActiveEvent& event)
{
	if(event.state & SDL_APPINPUTFOCUS)
	{
		active = (event.gain == 1);
	}
}

void Window::drawFrame()
{
	glClear( GL_COLOR_BUFFER_BIT);

	glMatrixMode( GL_MODELVIEW);
	glLoadIdentity();

	userInterface->draw();

	SDL_GL_SwapBuffers();
}
